package Processing;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import Catalogue.*;
import Middle.*;

/**
  * The order processing system.
  * @author  Michael Alexander Smith
  * @version 2.0
  */
 
public class Order implements OrderProcessing
{
  private static int theNextNumber = 1;          // Start at 1
  // Orders entered but waiting to be processed (picked)
  private ArrayList<SoldBasket>  inTransit 
                                 = new ArrayList<SoldBasket>(10);
  // Orders being processed (currently being picked)
  private ArrayList<SoldBasket>  processing 
                                 = new ArrayList<SoldBasket>(10);
  // Orders waiting to be collected by the customer
  private ArrayList<SoldBasket>  waiting 
                                 = new ArrayList<SoldBasket>(10);

  /**
   * Used for debug information
   *
   */

  private String asString( SoldBasket bl )
  {
    ByteArrayOutputStream bos = new ByteArrayOutputStream( 1024 );
    PrintStream ps = new PrintStream( bos );
    ps.printf( "#%d (", bl.getOrderNo() );
    ArrayList<Product> p = bl.getProducts();
    for ( Product pr: p )
    {
       ps.printf( "%s:%d ", pr.getDescription(), pr.getQuantity() );
    }
    ps.printf( ")" );
    return bos.toString();
  }

  /**
   * Generates a unique order number
   * @return A unique order number
   */

  public synchronized int uniqueNumber()
  {
    return theNextNumber++;
  }

  /**
   * Add a new order to the order processing system
   */

  public synchronized void newOrder( SoldBasket bought )
         throws OrderException
  {
    // You need to modify and fill in the correct code
	//System.out.println( "DEBUG: New order" );
	inTransit.add(bought);
  }

  /**
   * Returns an order to pick from the warehouse
   *  if no order then returns null.
   * @return An order to pick or null if none
   */

  public synchronized SoldBasket getOrderToPick()
         throws OrderException	
  {
	// You need to modify and fill in the correct code
    //System.out.println( "DEBUG: Get order to pick" );
    if(inTransit.size()>0){
    		if(processing.size()<2){
    		processing.add(inTransit.get(0));
    		inTransit.remove(0);
    		inTransit.trimToSize();
    		return processing.get(0);
    	}else{
    		return null;
    	}
    }else{
    	return null;
    	}
  }

  /**
   * Informs the order processing system that the order has been
   * picked and the products are now on the conveyor belt to
   * the shop floor.
   */

  public synchronized void informOrderPicked( int orderNo )
         throws OrderException
  {
    // You need to modify and fill in the correct code
    //System.out.println( "DEBUG: Order picked " + orderNo );
    if(processing.size()>0){
    waiting.add(processing.get(0));
    processing.remove(0);
    processing.trimToSize();
    }else{
    	return;
    }
  }

  /**
   * Informs the order processing system that the order has been
   * collected by the customer
   * @return true -> Order in system false -> no such order
   */

  public synchronized boolean informOrderCollected( int orderNo )
         throws OrderException
  {
	  boolean collected = false;
    // You need to modify and fill in the correct code
    //System.out.println( "DEBUG: Order collected " + orderNo );
    SoldBasket soldB;
    for(int i=0; i<waiting.size(); i++){
    	soldB = waiting.get(i);
    	if(soldB.getOrderNo() == orderNo){
    		collected = true;
    		waiting.remove(soldB);
    	}
    }
    if(collected){
    	return true;
    }else{
    	return false;
    }
  }

  /**
   * Returns information about all orders in the order processing system
   * This will consist of a map with the order numbers in the 3 queue
   * waiting, being picked, to be collected.
   * 1> Key "Waiting"       -> a list of orders waiting to be processed
   * 2> Key "BeingPicked"   -> a list of orders that are currently being picked
   * 3> Key "ToBeCollected" -> a list of orders that can now be collected
   * @return a Map with the keys: Waiting, BeingPicked, ToBeCollected
   */

  public synchronized Map<String, List<Integer> > getOrderState()
         throws OrderException
  {
    //System.out.println( "DEBUG: get state of order system" );
    Map < String, List<Integer> > res = 
      new HashMap< String, List<Integer> >();
    res.put( "InTransit",       orderNos(inTransit) );
    res.put( "Processing",   orderNos(processing) );
    res.put( "Waiting", orderNos(waiting) );

    return res;
  }
  
  public synchronized Map<String, ArrayList<SoldBasket> > getOrderArrays()
	         throws OrderException
	  {
	    //System.out.println( "DEBUG: get state of order system" );
	    Map < String, ArrayList<SoldBasket> > res = 
	      new HashMap< String, ArrayList<SoldBasket> >();
	    res.put( "InTransit",       inTransit);
	    res.put( "Processing",   processing);
	    res.put( "Waiting", waiting);

	    return res;
	  }
  
  private List< Integer > orderNos( ArrayList<SoldBasket> queue )
  {
    List <Integer> res = new ArrayList<Integer>();
    for ( SoldBasket sb: queue )
    {
      res.add( sb.getOrderNo() );
    }
    return res;
  }


}
